//////////////////////////////////////
// Fast Container Library           //
// MIT License - Copyright (c) 2012 //
//////////////////////////////////////

#pragma once

#include "common.h"
#include "algobase.h"

FC_NAMESPACE_BEGIN


template <class T>
struct scoped_ptr_deleter
{
	typedef T value_type;
	void operator()( const T* p ) const { delete p; }
};


template <class T>
struct scoped_array_ptr_deleter
{
	typedef T value_type;
	void operator()( const T* p ) const { delete [] p; }
};


/*
template <class T, class Allocator>
struct scoped_ptr_allocator_deleter
{
	typedef T value_type;
	typedef Allocator allocator_type;

	allocator_type a;
	void operator()( const T* p ) const { a.deallocate(p); }
};


template <class T, class Allocator>
struct scoped_array_allocator_deleter
{
	typedef T value_type;
	typedef Allocator allocator_type;

	allocator_type a;
	void operator()( const T* p ) const { a.deallocate(p); }
};
*/


// scoped_ptr

template < class T, class Deleter = scoped_ptr_deleter<T> > 
class scoped_ptr
{
public:
	typedef T					element_type;
	typedef scoped_ptr<T>		this_type;
	typedef Deleter				deleter_type;

	explicit scoped_ptr( T* p = 0 )
		: _ptr(p)
		{
		}

	~scoped_ptr()
		{
			delete_ptr();
		}

	operator bool() const { return _ptr != 0; }
	bool operator!() const { return _ptr == 0; }

	T& operator*() const { return *_ptr; }
	T* operator->() const { return _ptr; }
	T* get() const { return _ptr; }

	void reset( T* p = 0 )
	{
		if( p != _ptr )
		{
			delete_ptr();
			_ptr = p;
		}
	}
 
	void swap( scoped_ptr& x )
	{
		fc::swap( _ptr, x._ptr );
	}

	void delete_ptr() const
	{
		Deleter deleter;
		deleter(_ptr);
	}

protected:
	scoped_ptr( const scoped_ptr& );
	scoped_ptr& operator=( const scoped_ptr& );
	scoped_ptr& operator=( T* p );

	T* _ptr;
};



template <class T, class D> inline
	void swap( scoped_ptr<T, D>& a, scoped_ptr<T, D>& b )
	{
		a.swap(b);
	}

template <class T, class D>
	bool operator <(const scoped_ptr<T, D>& a, const scoped_ptr<T, D>& b)
	{
		return (a.get() < b.get());
	}




// scoped_array_ptr

template < class T, class Deleter = scoped_array_ptr_deleter<T> > 
class scoped_array_ptr
{
public:
	typedef T						element_type;
	typedef scoped_array_ptr<T>		this_type;
	typedef Deleter					deleter_type;

	explicit scoped_array_ptr( T* p = 0 )
		: _ptr(p)
		{
		}

	~scoped_array_ptr()
		{
			delete_ptr();
		}

	operator bool() const { return _ptr != 0; }
	bool operator!() const { return _ptr == 0; }

	T& operator*() const { return *_ptr; }
	T* operator->() const { return _ptr; }
	T* get() const { return _ptr; }

	T& operator[]( size_t i ) const { return _ptr[i]; }

	void reset( T* p = 0 )
	{
		if( p != _ptr )
		{
			delete_ptr();
			_ptr = p;
		}
	}
 
	void swap( scoped_array_ptr& x )
	{
		fc::swap( _ptr, x._ptr );
	}

	void delete_ptr() const
	{
		Deleter deleter;
		deleter(_ptr);
	}

protected:
	scoped_array_ptr( const scoped_array_ptr& );
	scoped_array_ptr& operator=( const scoped_array_ptr& );
	scoped_array_ptr& operator=( T* p );

	T* _ptr;
};



template <class T, class D> inline
	void swap( scoped_array_ptr<T, D>& a, scoped_array_ptr<T, D>& b )
	{
		a.swap(b);
	}

template <class T, class D>
	bool operator <( const scoped_array_ptr<T, D>& a, const scoped_array_ptr<T, D>& b )
	{
		return (a.get() < b.get());
	}




FC_NAMESPACE_END
